error 一个都不要多,一个都不能少

通过 SetFinalizer 在error 回收的时候,确认,错误有没被使用过,即调用 Error() 或者 Unwrap() 接口。

以确保,在不需要逐层打印错误的情况下。可以无脑返回错误信息。但是在最上层,将错误打印出来。

最外层,是最先被GC 到的。所以整个逻辑上来说,是没问题的。

应该要考虑的可能是对性能的损耗,待有空,再做压测吧。

我们先"优雅" 地将错误一层层包下去

简单实现示意

package main

import (
        "errors"
        "fmt"
        "runtime"
        "time"
)

type errWrap struct {
        err     error
        message string
        isUse   bool
}

func (e *errWrap) Error() string {
        runtime.SetFinalizer(e, nil)
        return e.message + " " + e.err.Error()
}

func (e *errWrap) Unwrap() error {
        runtime.SetFinalizer(e, nil)
        return e.err
}

func Wrap(msg string, err error) error {
        e := &errWrap{err: err, message: msg}
        runtime.SetFinalizer(e, func(w *errWrap) {
                if w.isUse {
                        return
                }
                fmt.Printf("error %s\n", w)
        })
        return e
}

func do() {
        err := fmt.Errorf("hello")

        err2 := Wrap("wrap", err)
        Wrap("wrap never use", err)
        fmt.Printf("err %s\n", err2)
        fmt.Printf("err %s\n", errors.Unwrap(err2))
        err = nil
        err2 = nil
}

func main() {
        do()
        runtime.GC()
        time.Sleep(time.Second * 1)
}

注意: Wrap(“wrap never use”, err) 这行包的错误,从来没有使用。在实际中,他就是被遗忘的错误。

导致结果就是,没有人能注意到它们。

爱的反面,不是恨(打日志),而是遗忘(啥也没有)

参考:

  1. https://github.com/pkg/errors
  2. https://pkg.go.dev/errors
humboldt Written by:

humboldt 的趣味程序园